package per.chenxin.tools.foundation;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

public class ResultSetData {

    Connection connection;

    Statement statement;

    ResultSet resultSet;

    public List<Object[]> data;

    MetaData[] metaDatas;

    int count;

    long executeTime;

    public SortedSet<Integer> setUpdate;

    public SortedSet<Object[]> setDelete;

    public ResultSetData(Connection connection, String strSql, int intCount) throws SQLException {

        this.connection = connection;
        statement = connection.createStatement();
        count = (intCount == -1 ? DBUtil.getResultCount(statement, strSql) : intCount);
        long longTimeStart = System.currentTimeMillis();
        resultSet = statement.executeQuery(strSql);
        executeTime = System.currentTimeMillis() - longTimeStart;
        metaDatas = DBUtil.getMetaDatas(resultSet.getMetaData());
        data = new ArrayList<Object[]>();
        setUpdate = Collections.synchronizedSortedSet(new TreeSet<Integer>());
        setDelete = Collections.synchronizedSortedSet(new TreeSet<Object[]>());
    }

    public ResultSetData(Connection connection, String strSql) throws SQLException {

        this(connection, strSql, -1);
    }

    public void appendAll() throws SQLException {

        while (append())
            ;

    }

    public int append(int count) throws SQLException {

        int i = 0;
        for (; i < count; i++) {
            if (!append()) {
                return i;
            }
        }
        return i;
    }

    public boolean append() throws SQLException {

        if (resultSet == null) {
            return false;
        }

        if (!resultSet.next()) {
            resultSet.close();
            resultSet = null;
            return false;
        }

        Object[] objs = new Object[metaDatas.length];
        for (int i = 0; i < metaDatas.length; i++) {

            objs[i] = DBUtil.getValueFromResultSet(metaDatas[i], resultSet, i + 1);
        }
        data.add(objs);
        return true;

    }

    public Object[] getDataItem(int index) {

        return data.get(index);
    }

    public List<Object[]> getData() {

        return data;
    }

    public void sort(final int indexSortColumn, final int sortDirection) {

        if (indexSortColumn < 0 || indexSortColumn >= metaDatas.length)
            return;

        if (!(sortDirection != Constants.UP || sortDirection != Constants.DOWN))
            return;

        //        List<Object[]> dest = new ArrayList<Object[]>();
        //        for (Object[] objs : data) {
        //            dest.add(objs.clone());
        //        }

        Collections.sort(data, new Comparator<Object[]>() {

            @SuppressWarnings("unchecked")
            @Override
            public int compare(Object[] o1, Object[] o2) {

                if (Comparable.class.isInstance(o1[indexSortColumn])) {
                    switch (sortDirection) {
                        case Constants.UP:

                            return ((Comparable<Object>) o1[indexSortColumn]).compareTo(o2[indexSortColumn]);

                        case Constants.DOWN:

                            return ((Comparable<Object>) o2[indexSortColumn]).compareTo(o1[indexSortColumn]);

                        default:
                            return 0;
                    }

                } else {
                    return compareTo(o1[indexSortColumn].toString(),
                        o2[indexSortColumn].toString(), sortDirection);
                }

            }

            int compareTo(String s1, String s2, int sortDirection) {

                switch (sortDirection) {
                    case Constants.UP:

                        return s1.compareTo(s2);

                    case Constants.DOWN:

                        return s2.compareTo(s1);

                    default:
                        return 0;
                }

            }

        });

        return;

    }

    public void update(int[] indices, String[][] values, String table, DBTable dbTable) {

        for (int i = 0; i < indices.length; i++) {
            update(indices[i], values[i], table, dbTable);
        }

    }

    public void update(int index, String[] value, String table, DBTable dbTable) {

        if (setUpdate.contains(index)) {
            System.out.println(DBUtil.createUpdateSql(dbTable, table, value));

            try {
                DBUtil.executeUpdate(connection, DBUtil.createInsertSql(value, metaDatas, table));
                setUpdate.remove(index);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    public void delete(int[] indices) {

        for (int i = indices.length - 1; i >= 0; i--) {
            delete(indices[i]);
        }
    }

    public void delete(int index) {

        setDelete.add(data.get(index).clone());
        data.remove(index);

    }

    public void duplicate(int[] indices, int target) {

        for (int index : indices) {
            duplicate(index, target++);
        }

    }

    public void duplicate(int index, int target) {

        Object[] objs = data.get(index);
        Object[] newObjs = Arrays.copyOf(objs, objs.length);
        data.add(target, newObjs);

        SortedSet<Integer> setHead = setUpdate.headSet(target);
        SortedSet<Integer> setTail = setUpdate.tailSet(target);

        SortedSet<Integer> setUpdateNew = Collections.synchronizedSortedSet(new TreeSet<Integer>());

        Iterator<Integer> iterator = setHead.iterator();
        while (iterator.hasNext()) {
            Integer row = iterator.next();
            setUpdateNew.add(new Integer(row));
        }

        iterator = setTail.iterator();
        while (iterator.hasNext()) {
            Integer row = iterator.next();
            setUpdateNew.add(new Integer(row + 1));
        }

        setUpdate = setUpdateNew;
        setUpdate.add(new Integer(target));

    }

    public MetaData[] getMetaDatas() {

        return metaDatas;
    }

    @Override
    protected void finalize() throws Throwable {

        DBUtil.closeResultSet(resultSet);
        DBUtil.closeStatement(statement);
        super.finalize();
    }

}
